//
// Created by QU on 2023/12/25.
//

// c++ standard library
#include <cassert>
#include <iostream>
#include <list>
#include <vector>
#include <map>
#include <set>


// boost library
#include <boost/smart_ptr.hpp>
#include <boost/smart_ptr/owner_less.hpp>
#include <boost/smart_ptr/weak_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

// using namespace
using std::cin, std::cout, std::endl;
using boost::shared_ptr;
using boost::weak_ptr;

class self_shared : public boost::enable_shared_from_this<self_shared>   // 一个需要使用shared_ptr进行管理的类.
{
public:
    self_shared(int n): x(n){}
    int x;
    void print(){
        cout << "self_shared: " << x << endl;
    }
};

class node {
public:
    ~node(){ cout << "deleted" << endl;}
//     typedef shared_ptr<node> shared_node_p;
//    shared_node_p next;
    typedef weak_ptr<node> weaked_node_p;
    weaked_node_p next;
};


int main(int argc, char* argv[]){
    // weak_ptr被设计成shared_ptr的协同配合指针. 可以从另一个shared_ptr或者另一个weak_ptr对象构造获得资源的观测权.
    // 但是weak_ptr没有共享资源,他的构造不会导致导致引用计数的减少, 只是一个"静静的观察者".

    //    weak_ptr可以使用成员函数use_count()观察资源的引用计数.
    //    weak_ptr没有operator.()和operator->()也就意味着没有可以访问成员指针的方法,
    //    但是可以使用一个重要的函数lock()获得一个被观测的smart_ptr的对象.

    shared_ptr<int> sp(new int(10));
    assert(sp.use_count() == 1);
    assert(sp);

    weak_ptr<int> wp(sp);
    assert(wp.use_count() == 1);
    assert(!wp.empty());

    if(!wp.expired()) {
        shared_ptr<int> sp2 = wp.lock();    // 获得一个shared_ptr
        *sp2 = 100;
        assert(wp.use_count() == 2);
    }

    cout << *sp << endl;


    assert(wp.use_count() == 1);
    sp.reset();
    assert(wp.expired());
    assert(!wp.lock());     // 获得新的shared_ptr是空的.

    ////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 对象自我管理

//    weak_ptr的一个重要用途是通过this指针的shared_ptr, 使对象能够通过生产shared_ptr管理自己.
//    对象使用weak_ptr观测this指针, 这并不影响引用计数, 需要的时候就使用lock()返回一个符合要求的shared_ptr, 供外界调用.
//  这个解决方案是一个惯用的解决方法, 在<boost/enable_shared_from_this.hpp>定义一个助手类 enable_shared_this<T>,
//  使用weak_ptr的时候只需要让被shared_ptr使用的类继承它即可,成员函数shared_from_this()会返回指针的shared_ptr.

    auto self_shared_ptr1 = boost::make_shared<self_shared>(10);
    self_shared_ptr1->print();

    auto self_shared_ptr2 = self_shared_ptr1->shared_from_this();
    self_shared_ptr2->x = 1000;
    self_shared_ptr2->print();
    // 注意: 千万不要对普通对象(非shared_ptr管理的对象)使用shared_from_this()函数.
    // 编译没有问题, 但是运行过程中会导致shared_ptr在析构的时候企图删除一个栈上的对象而导致未定义行为.

//    错误的
//    self_shared ss;
//    ss.shared_from_this();


    // 打破循环引用 **
    // 有时候代码中出现了循环引用, 这个时候可能导致shared_ptr的引用计数的机制可能失效, 最终导致资源不能正确的被释放.

    // 下面是一个引用计数的示例:
    auto node_p1 = boost::make_shared<node>();
    auto node_p2 = boost::make_shared<node>();

    // 形成依赖关系.
    node_p1->next = node_p2;
    node_p2->next = node_p1;

    // 这样外部的main函数中持有一个计数, class内部的实例持有一个计数, 这样永远就是2.

    // 这个时候查看引用计数的时候
//    assert(node_p1.use_count() == 2);
//    assert(node_p2.use_count() == 2);
    // 最终导致这部分的资源不能得到争正确的释放, 最终结束的时候, 操作系统kill.

    // 这个时候我们可以使用不增加引用计数的weak_ptr代替类中的shared_ptr.
    // 在真正需要shared_ptr的时候调用lock函数.

    // 将上面的内容进行修改. 使用weak_ptr存储next, 不增加use_count计数.
    assert(node_p1.use_count() == 1);
    assert(node_p2.use_count() == 1);

    // 调用lock函数，尝试获取shared_ptr
    auto locked_node_p1 = node_p1->next.lock();
    auto locked_node_p2 = node_p2->next.lock();

    // 现在再次检查引用计数
    assert(node_p1.use_count() == 2);
    assert(node_p2.use_count() == 2);
    // 最后出现了deleted.  表示资源被正确的释放.

}


